#include "block_map.h"
#include "../utils/Lock.h"
#include "../utils/util.h"
#include "define.h"

namespace PFS
{
    BlockMap::BlockMap()
    {}
    BlockMap::~BlockMap()
    { 
        remove_all();
    }

    BlockLocate* BlockMap::insert(const uint32_t block_id, const BlockLocate* block, const bool overwrite)
    {
        BlockLocate *old_block = NULL;
        return_val_if_fail(block_id != 0, NULL);
        BLOCK_MAP_ITER it = this->block_map.find(block_id);
        if(it != block_map.end())
        {
            if(overwrite)
            {
                old_block = it->second;
                block_map.erase(it);
            }
            else
                return NULL;
        }
        block_map[block_id] = block;

        return old_block;
    }

    bool BlockMap::exsit(uint32_t block_id) const
    {
        BLOCK_MAP::const_iterator it = block_map.find(block_id);
        return it != block_map.end();
    }

    BlockLocate* BlockMap::find(uint32_t block_id)
    {
        BLOCK_MAP_ITER it = block_map.find(block_id);
        if(it == block_map.end())
            return NULL;
        else
            return it->second;
    }

    BlockLocate* BlockMap::create(const uint32_t block_id, bool insert)
    {
        BlockLocate* block = new BlockLocate();
        BlockInfo* block_info = block->get_block_info();
        memset(block_info, 0, sizeof(BlockInfo));

        block_info->block_id = block_id;
        block_info->version = 0;
        if(insert)
            block_map[block_id] = block;
        return block;
    }

    bool BlockMap::remove(const uint32_t block_id)
    {
        BLOCK_MAP_ITER it = block_map.find(block_id);
        if(it == block_map.end())
            return false;
        delete it->second;
        block_map.erase(it);
        return true;
    }

    bool BlockMap::connect(const uint32_t block_id, const uint64_t server_id, const bool is_master)
    {
        BLOCK_MAP_ITER it = block_map.find(block_id);
        if(it == block_map.end())
        {
            cout<<"block "<<block_id<<" not found in blockmap\n";
            return false;
        }

        if(!it->second->join(server_id, is_master))
        {
            cout<<"block "<<block_id<<" join failed\n";
            return false;
        }
        if(is_master)
            it->second->set_master_data_server(server_id);
        return true;
    }


    bool BlockMap::release(uint32_t block_id, uint64_t server_id)
    {
        BLOCK_MAP_ITER it = block_map.find(block_id);
        if(it == block_map.end())
            return false;
        if(it->second->get_master_data_server() == server_id)
            it->second->set_master_data_server(0);
        return it->second->leave(server_id);
    }

    void BlockMap::remove_all()
    {
        for(BLOCK_MAP_ITER it = block_map.begin(); it != block_map.end(); it++)
            delete it->second;
        block_map.clear();
    }

    uint32_t BlockMap::get_max_block_id() const
    {
        uint32_t block_id = 0;
        for(BLOCK_MAP::const_iterator it = block_map.begin(); it != block_map.end(); it++)
        {
            if(block_id < it->first)
                block_id = it->first;
        }
        return block_id;
    }

    uint64_t BlockMap::get_all_block_bytes() const
    {
        uint64 total = 0;
        for(BLOCK_MAP::const_iterator it = block_map.begin(); it != block_map.end(); it++)
            total += it->second->get_block_info()->size();
        return total;
    }

}
